#include "serial_port.h"

#include <iostream>
#include <chrono>
#include <string.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/time.h>
#endif

// 构造函数
SerialPort::SerialPort() : isOpen_(false), timeout_(1000), isReading_(false) {
#ifdef _WIN32
  handle_ = INVALID_HANDLE_VALUE;
#else
  fd_ = -1;
#endif
}

// 带配置的构造函数
SerialPort::SerialPort(const Config &config)
    : config_(config), isOpen_(false), timeout_(1000), isReading_(false) {
#ifdef _WIN32
  handle_ = INVALID_HANDLE_VALUE;
#else
  fd_ = -1;
#endif
  open(config);
}

// 析构函数
SerialPort::~SerialPort() {
  if (isOpen_) {
    close();
  }
}

// 打开串口
bool SerialPort::open(const Config &config) {
  config_ = config;
  return open(config.port, config.baudRate);
}

// 使用端口名和波特率打开串口
bool SerialPort::open(const std::string &port, int baudRate) {
  if (isOpen_) {
    close();
  }

#ifdef _WIN32
  // Windows平台的串口打开
  std::string portName = "\\\\.\\" + port;
  handle_ = CreateFileA(portName.c_str(), GENERIC_READ | GENERIC_WRITE,
                        0,              // 独占访问
                        NULL,           // 默认安全属性
                        OPEN_EXISTING,  // 打开已有端口
                        0,              // 非重叠I/O
                        NULL            // 非模板文件
  );

  if (handle_ == INVALID_HANDLE_VALUE) {
    std::cerr << "无法打开串口: " << port << ", 错误代码: " << GetLastError()
              << std::endl;
    return false;
  }

  // 配置串口参数
  DCB dcbSerialParams = {0};
  dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

  if (!GetCommState(handle_, &dcbSerialParams)) {
    std::cerr << "获取串口配置失败，错误代码: " << GetLastError() << std::endl;
    CloseHandle(handle_);
    handle_ = INVALID_HANDLE_VALUE;
    return false;
  }

  // 设置波特率
  dcbSerialParams.BaudRate = baudRate;

  // 配置数据位、停止位和校验位
  dcbSerialParams.ByteSize = config_.dataBits;

  switch (config_.stopBits) {
    case 1:
      dcbSerialParams.StopBits = ONESTOPBIT;
      break;
    case 2:
      dcbSerialParams.StopBits = TWOSTOPBITS;
      break;
    default:
      dcbSerialParams.StopBits = ONESTOPBIT;
      break;
  }

  switch (config_.parity) {
    case 0:
      dcbSerialParams.Parity = NOPARITY;
      break;
    case 1:
      dcbSerialParams.Parity = ODDPARITY;
      break;
    case 2:
      dcbSerialParams.Parity = EVENPARITY;
      break;
    default:
      dcbSerialParams.Parity = NOPARITY;
      break;
  }

  // 设置流控制
  switch (config_.flowControl) {
    case 0:
      dcbSerialParams.fOutxCtsFlow = FALSE;
      dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
      dcbSerialParams.fOutX = FALSE;
      dcbSerialParams.fInX = FALSE;
      break;
    case 1:
      dcbSerialParams.fOutxCtsFlow = FALSE;
      dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
      dcbSerialParams.fOutX = TRUE;
      dcbSerialParams.fInX = TRUE;
      break;
    case 2:
      dcbSerialParams.fOutxCtsFlow = TRUE;
      dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
      dcbSerialParams.fOutX = FALSE;
      dcbSerialParams.fInX = FALSE;
      break;
    default:
      dcbSerialParams.fOutxCtsFlow = FALSE;
      dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
      dcbSerialParams.fOutX = FALSE;
      dcbSerialParams.fInX = FALSE;
      break;
  }

  if (!SetCommState(handle_, &dcbSerialParams)) {
    std::cerr << "设置串口配置失败，错误代码: " << GetLastError() << std::endl;
    CloseHandle(handle_);
    handle_ = INVALID_HANDLE_VALUE;
    return false;
  }

  // 设置超时
  COMMTIMEOUTS timeouts = {0};
  timeouts.ReadIntervalTimeout = 50;
  timeouts.ReadTotalTimeoutConstant = timeout_;
  timeouts.ReadTotalTimeoutMultiplier = 10;
  timeouts.WriteTotalTimeoutConstant = timeout_;
  timeouts.WriteTotalTimeoutMultiplier = 10;

  if (!SetCommTimeouts(handle_, &timeouts)) {
    std::cerr << "设置串口超时失败，错误代码: " << GetLastError() << std::endl;
    CloseHandle(handle_);
    handle_ = INVALID_HANDLE_VALUE;
    return false;
  }

#else
  // Unix平台的串口打开
  fd_ = ::open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

  if (fd_ == -1) {
    std::cerr << "无法打开串口: " << port << ", 错误: " << strerror(errno)
              << std::endl;
    return false;
  }

  // 获取当前串口配置
  struct termios tty;
  memset(&tty, 0, sizeof(tty));

  if (tcgetattr(fd_, &tty) != 0) {
    std::cerr << "获取串口属性失败: " << strerror(errno) << std::endl;
    ::close(fd_);
    fd_ = -1;
    return false;
  }

  // 设置波特率
  speed_t baud;
  switch (baudRate) {
    case 9600:
      baud = B9600;
      break;
    case 19200:
      baud = B19200;
      break;
    case 38400:
      baud = B38400;
      break;
    case 57600:
      baud = B57600;
      break;
    case 115200:
      baud = B115200;
      break;
    case 230400:
      baud = B230400;
      break;
    default:
      std::cerr << "不支持的波特率: " << baudRate << std::endl;
      ::close(fd_);
      fd_ = -1;
      return false;
  }

  cfsetispeed(&tty, baud);
  cfsetospeed(&tty, baud);

  // 设置数据位
  tty.c_cflag &= ~CSIZE;
  switch (config_.dataBits) {
    case 5:
      tty.c_cflag |= CS5;
      break;
    case 6:
      tty.c_cflag |= CS6;
      break;
    case 7:
      tty.c_cflag |= CS7;
      break;
    case 8:
      tty.c_cflag |= CS8;
      break;
    default:
      tty.c_cflag |= CS8;
      break;
  }

  // 设置校验位
  switch (config_.parity) {
    case 0:  // 无校验
      tty.c_cflag &= ~PARENB;
      tty.c_cflag &= ~PARODD;
      break;
    case 1:  // 奇校验
      tty.c_cflag |= PARENB;
      tty.c_cflag |= PARODD;
      break;
    case 2:  // 偶校验
      tty.c_cflag |= PARENB;
      tty.c_cflag &= ~PARODD;
      break;
    default:  // 默认无校验
      tty.c_cflag &= ~PARENB;
      tty.c_cflag &= ~PARODD;
      break;
  }

  // 设置停止位
  switch (config_.stopBits) {
    case 1:
      tty.c_cflag &= ~CSTOPB;
      break;
    case 2:
      tty.c_cflag |= CSTOPB;
      break;
    default:
      tty.c_cflag &= ~CSTOPB;
      break;
  }

  // 设置流控制
  switch (config_.flowControl) {
    case 0:  // 无流控制
      tty.c_cflag &= ~CRTSCTS;
      tty.c_iflag &= ~(IXON | IXOFF | IXANY);
      break;
    case 1:  // 软件流控制
      tty.c_cflag &= ~CRTSCTS;
      tty.c_iflag |= (IXON | IXOFF | IXANY);
      break;
    case 2:  // 硬件流控制
      tty.c_cflag |= CRTSCTS;
      tty.c_iflag &= ~(IXON | IXOFF | IXANY);
      break;
    default:  // 默认无流控制
      tty.c_cflag &= ~CRTSCTS;
      tty.c_iflag &= ~(IXON | IXOFF | IXANY);
      break;
  }

  // 设置为原始模式
  tty.c_cflag |= (CLOCAL | CREAD);
  tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG | IEXTEN);
  tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
  tty.c_oflag &= ~OPOST;

  // 设置超时
  tty.c_cc[VMIN] = 0;
  tty.c_cc[VTIME] = timeout_ / 100;  // 单位是 1/10 秒

  // 应用设置
  if (tcsetattr(fd_, TCSANOW, &tty) != 0) {
    std::cerr << "设置串口属性失败: " << strerror(errno) << std::endl;
    ::close(fd_);
    fd_ = -1;
    return false;
  }

  // 刷新缓冲区
  tcflush(fd_, TCIOFLUSH);
#endif

  isOpen_ = true;
  return true;
}

// 关闭串口
void SerialPort::close() {
  if (!isOpen_) {
    return;
  }

  // 如果正在读取，先停止
  if (isReading_) {
    stopReading();
  }

#ifdef _WIN32
  if (handle_ != INVALID_HANDLE_VALUE) {
    CloseHandle(handle_);
    handle_ = INVALID_HANDLE_VALUE;
  }
#else
  if (fd_ != -1) {
    ::close(fd_);
    fd_ = -1;
  }
#endif

  isOpen_ = false;
}

// 检查串口是否已打开
bool SerialPort::isOpen() const { return isOpen_; }

// 写入数据
int SerialPort::write(const uint8_t *data, size_t size) {
  if (!isOpen_) {
    return -1;
  }

#ifdef _WIN32
  DWORD bytesWritten = 0;
  if (!WriteFile(handle_, data, static_cast<DWORD>(size), &bytesWritten,
                 NULL)) {
    std::cerr << "写入串口失败，错误代码: " << GetLastError() << std::endl;
    return -1;
  }
  return static_cast<int>(bytesWritten);
#else
  int bytesWritten = ::write(fd_, data, size);
  if (bytesWritten < 0) {
    std::cerr << "写入串口失败: " << strerror(errno) << std::endl;
    return -1;
  }
  return bytesWritten;
#endif
}

// 写入数据（vector版本）
int SerialPort::write(const std::vector<uint8_t> &data) {
  return write(data.data(), data.size());
}

// 读取数据
int SerialPort::read(uint8_t *buffer, size_t size) {
  if (!isOpen_) {
    return -1;
  }

#ifdef _WIN32
  DWORD bytesRead = 0;
  if (!ReadFile(handle_, buffer, static_cast<DWORD>(size), &bytesRead, NULL)) {
    std::cerr << "读取串口失败，错误代码: " << GetLastError() << std::endl;
    return -1;
  }
  return static_cast<int>(bytesRead);
#else
  int bytesRead = ::read(fd_, buffer, size);
  if (bytesRead < 0 && errno != EAGAIN) {
    std::cerr << "读取串口失败: " << strerror(errno) << std::endl;
    return -1;
  }
  return bytesRead;
#endif
}

// 读取数据（vector版本）
std::vector<uint8_t> SerialPort::read(size_t maxSize) {
  std::vector<uint8_t> data(maxSize, 0);
  int bytesRead = read(data.data(), maxSize);

  if (bytesRead > 0) {
    data.resize(bytesRead);
    return data;
  } else {
    return std::vector<uint8_t>();
  }
}

// 设置超时时间
void SerialPort::setTimeout(int milliseconds) {
  timeout_ = milliseconds;

  if (!isOpen_) {
    return;
  }

#ifdef _WIN32
  COMMTIMEOUTS timeouts = {0};
  timeouts.ReadIntervalTimeout = 50;
  timeouts.ReadTotalTimeoutConstant = timeout_;
  timeouts.ReadTotalTimeoutMultiplier = 10;
  timeouts.WriteTotalTimeoutConstant = timeout_;
  timeouts.WriteTotalTimeoutMultiplier = 10;

  SetCommTimeouts(handle_, &timeouts);
#else
  struct termios tty;
  if (tcgetattr(fd_, &tty) != 0) {
    return;
  }

  tty.c_cc[VTIME] = timeout_ / 100;  // 单位是 1/10 秒
  tcsetattr(fd_, TCSANOW, &tty);
#endif
}

// 清空串口缓冲区
void SerialPort::flush() {
  if (!isOpen_) {
    return;
  }

#ifdef _WIN32
  PurgeComm(handle_, PURGE_RXCLEAR | PURGE_TXCLEAR);
#else
  tcflush(fd_, TCIOFLUSH);
#endif
}

// 设置数据接收回调
void SerialPort::setDataCallback(DataCallback callback) {
  dataCallback_ = callback;
}

// 开始异步读取
bool SerialPort::startReading() {
  if (!isOpen_ || isReading_) {
    return false;
  }

  isReading_ = true;
  readThread_ = std::thread(&SerialPort::readThreadFunc, this);
  return true;
}

// 停止异步读取
void SerialPort::stopReading() {
  if (!isReading_) {
    return;
  }

  isReading_ = false;
  if (readThread_.joinable()) {
    readThread_.join();
  }
}

// 读取线程函数
void SerialPort::readThreadFunc() {
  constexpr size_t bufferSize = 1024;
  std::vector<uint8_t> buffer(bufferSize);

  while (isReading_) {
    // 读取数据
    int bytesRead = read(buffer.data(), buffer.size());

    // 处理读取到的数据
    if (bytesRead > 0) {
      buffer.resize(bytesRead);

      // 调用回调函数处理数据
      if (dataCallback_) {
        dataCallback_(buffer);
      }

      // 重置缓冲区大小
      buffer.resize(bufferSize);
    }

    // 短暂休眠，避免CPU占用过高
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
  }
}